<div class="tmd-doc">
<p></p>
<h1 class="tmd-header-1">
<code class="tmd-code-span">strings.Builder</code> iteration variables in traditional 3-clause <code class="tmd-code-span">for;;</code> loops are implemented incorrectly
</h1>
<p></p>
<div class="tmd-usual">
Go 1.22 changed the semantics of <code class="tmd-code-span">for</code> loops, including both <code class="tmd-code-span">for-range</code> loops and traditional 3-clause <code class="tmd-code-span">for ..; ..; .. {...}</code> loops. For details, please read <a href="https://go101.org/blog/2024-03-01-for-loop-semantic-changes-in-go-1.22.html"><code class="tmd-code-span">for</code> Loop Semantic Changes in Go 1.22: Be Aware of the Impact</a>.
</div>
<p></p>
<p></p>
<div class="tmd-usual">
In my honest opinion, the overall impact of the new semantics of <code class="tmd-code-span">for-range</code> loops is positive, while the overall impact of the new semantics of traditional 3-clause <code class="tmd-code-span">for;;</code> loops is negative. The above referenced article shows the all the bad effects of the semantic change of traditional 3-clause <code class="tmd-code-span">for;;</code> loops I have found so far.
</div>
<p></p>
<div class="tmd-usual">
One fact is that, currently, the latest official Go toolchain doesn't implement the new semantics correctly for some cases in which <code class="tmd-code-span">strings.Builder</code> values are used as (freshly-declared) iteration variables of traditional 3-clause <code class="tmd-code-span">for;;</code> loops. The following example shows one such case:
</div>
<p></p>
<pre class="tmd-code">
<code class="language-Go">package main

import (
	"fmt"
	"strings"
)

func foo() string {
	for b, i := (strings.Builder{}), byte('a'); ; i++ {
		b.WriteByte(i) // not panic
		if i == 'z' {
			return b.String()
		}
	}
}

func bar(callback func(*strings.Builder)) string {
	for b, i := (strings.Builder{}), byte('a'); ; i++ {
		b.WriteByte(i) // panics here
		callback(&amp;b)
		if i == 'z' {
			return b.String()
		}
	}
}

func main() {
	fmt.Println(foo())
	debugProcess := func(pb *strings.Builder) {
		//fmt.Println(pb.String()) // do nothing
	}
	fmt.Println(bar(debugProcess))
}
</code></pre>
<p></p>
<div class="tmd-usual">
The above example program doesn't panic with official Go toolchain versions prior to v1.22: <sup><a id="fn:gotv:ref-1" href="#fn:gotv">[1]</a></sup>
</div>
<p></p>
<pre class="tmd-code">
$ gotv 1.21 run main.go
[Run]: $HOME/.cache/gotv/tag_go1.21.12/bin/go run main.go
abcdefghijklmnopqrstuvwxyz
abcdefghijklmnopqrstuvwxyz
</pre>
<p></p>
<div class="tmd-usual">
However, when with official Go toolchain v1.22+, the example program panics:
</div>
<p></p>
<pre class="tmd-code">
$ gotv 1.22 run main.go
[Run]: $HOME/.cache/gotv/tag_go1.22.5/bin/go run main.go
abcdefghijklmnopqrstuvwxyz
panic: strings: illegal use of non-zero Builder copied by value
</pre>
<p></p>
<div class="tmd-usual">
The behaviors of the <code class="tmd-code-span">foo</code> and <code class="tmd-code-span">bar</code> functions should be consistent with each other, but official Go toolchain v1.22+ fail to make the guarantee. In fact, by the Go 1.22+ new semantics, both of the <code class="tmd-code-span">foo</code> and <code class="tmd-code-span">bar</code> functions should produce a panic, because nocopy values should not be used as (freshly declared) iteration variables since Go 1.22.
</div>
<p></p>
<div class="tmd-usual">
Nite: the <code class="tmd-code-span">go vet</code> command provided in Go toolchain 1.22 and 1.23 versions failed to warn on such cases.
</div>
<p></p>
<div class="tmd-usual">
The Go core team <a href="https://github.com/golang/go/issues/66070#issuecomment-1981642904">refused to fix this bug</a>. You should be aware of this bug.
</div>
<p></p>
<p></p>
<hr  class="tmd-seperator"/>
<p></p>

<ol class="tmd-list tmd-footnotes" id="fn:">
<li id="fn:gotv" class="tmd-list-item tmd-footnote-item">
<div id="gotv" class="tmd-usual">
GoTV (<a href="https://go101.org/apps-and-libs/gotv.html">https://go101.org/apps-and-libs/gotv.html</a>) is a tool used to install and use coexisting installations of Go toolchain verisons harmoniously.
</div>
<a href="#fn:gotv:ref-1">↩︎</a></li>
</ol>
</div>
